/**
 * Copyright (C) 2013-2014 the original author or authors.
 */
package com.foreveross.bsl.mam.rbac.web;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.databind.JavaType;
import com.foreveross.bsl.common.utils.mapper.JsonMapper;
import com.foreveross.bsl.common.utils.web.QueryFilter;
import com.foreveross.bsl.common.utils.web.QuerySpecs;
import com.foreveross.bsl.common.utils.web.model.PageMustache;
import com.foreveross.bsl.common.utils.web.model.QueryModelHelper;
import com.foreveross.bsl.common.utils.web.model.SelectBoxModel;
import com.foreveross.bsl.common.utils.web.model.SortInfoModel;
import com.foreveross.bsl.mam.app.application.AppMainApplication;
import com.foreveross.bsl.mam.app.application.vo.AppMainVo;
import com.foreveross.bsl.mam.model.application.WidgetApplication;
import com.foreveross.bsl.mam.model.application.vo.WidgetVO;
import com.foreveross.bsl.mam.rbac.application.OperationApplication;
import com.foreveross.bsl.mam.rbac.application.PrivilegeApplication;
import com.foreveross.bsl.mam.rbac.application.RbacUserRoleApplication;
import com.foreveross.bsl.mam.rbac.application.RoleApplication;
import com.foreveross.bsl.mam.rbac.application.UserApplication;
import com.foreveross.bsl.mam.rbac.application.vo.OperationVO;
import com.foreveross.bsl.mam.rbac.application.vo.PrivilegeVO;
import com.foreveross.bsl.mam.rbac.application.vo.RoleVO;
import com.foreveross.bsl.mam.rbac.application.vo.UserVO;
import com.foreveross.bsl.push.application.PushService;
import com.foreveross.bsl.push.application.vo.MessageParams;
import com.foreveross.bsl.push.application.vo.MessageVo;
import com.foreveross.bsl.push.application.vo.ReceiverTypeEnumVo;
import com.foreveross.bsl.system.application.ApplicationRegisterApplication;

/**
 * <BR>
 * [功能详细描述]
 * 
 * @author Amberlo
 * @version [bsl-web , 2013-6-24]
 */
@Controller
@RequestMapping("/rbac/privilege")
public class PrivilegeController extends RbacBaseController {
	private Logger log = Logger.getLogger(getClass());
	@Inject
	private RoleApplication roleApplication;
	@Inject
	private PrivilegeApplication privilegeApplication;
	@Inject
	private OperationApplication operationApplication;
	@Inject
	private UserApplication userApplication;
	@Inject
	private AppMainApplication appApplication;
	@Inject
	private RbacUserRoleApplication rbacApplication;
	@Inject
	private WidgetApplication widgetApplication;

	@Inject
	private PushService pushService;

	@Inject
	private ApplicationRegisterApplication applicationRegisterApplication;

	private String checkUnique(RoleVO role) {
		String msg = null;
		boolean isRoleIdExsit = checkRoleNameUnique(role.getRolename());
		boolean isRoleNameExsit = checkRoleChnNameUnique(role.getName());
		if (isRoleIdExsit) {
			msg = "角色ID已经存在";
		}

		if (isRoleNameExsit) {
			msg = "角色名已经存在";
		}
		return msg;
	}

	private boolean checkRoleNameUnique(String rolename) {
		if (roleApplication.getRoleByRoleName(rolename) != null) {
			return true;
		} else
			return false;
	}

	private boolean checkRoleChnNameUnique(String roleChnName) {
		if (roleApplication.getRoleByName(roleChnName) != null) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * ---------------------------------------------------基本方法------------------
	 * ---------------------------------------------
	 */
	/**
	 * 增加权限
	 * 
	 * @param role
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/add")
	public Map<String, String> add(RoleVO role) {
		Map<String, String> result = new HashMap<String, String>();
		roleApplication.saveEntity(role);
		result.put("result", "success");
		return result;
	}

	/**
	 * 增加权限
	 * 
	 * @param role
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/getRole")
	public RoleVO getRole(String id) {
		if (id == null || id.equals(""))
			return null;
		return roleApplication.getEntity(id);
	}

	/**
	 * 查询所有角色
	 * 
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/findAllRole")
	public List<RoleVO> getAllRoles() {
		List<RoleVO> roles = roleApplication.findAll();
		return roles;
	}

	/**
	 * 增加角色
	 * 
	 * @param role
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/addRole")
	public Map<String, String> addRole(RoleVO role) {
		Map<String, String> result = new HashMap<String, String>();

		// 检查唯一性约束
		String msg = checkUnique(role);

		if (msg != null) {
			result.put("message", msg);
			result.put("result", "error");
			return result;
		}

		roleApplication.saveEntity(role);
		result.put("result", "success");
		return result;
	}

	/**
	 * 编辑角色
	 * 
	 * @param role
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/updateRole")
	public Map<String, String> updateRole(RoleVO role) {
		Map<String, String> result = new HashMap<String, String>();
		String msg = null;
		// 查询修改前的角色实体
		RoleVO remoteRole = roleApplication.getEntity(role.getId());
		if (remoteRole == null) {
			msg = "修改异常，不存在角色";
		}
		boolean isEditRolename = !(role.getRolename().equals(remoteRole
				.getRolename()));
		boolean isEditRoleChnName = !(role.getName().equals(remoteRole
				.getName()));
		if (isEditRolename) {
			// 角色名有作修改，检查角色中文名的唯一性
			if (isEditRoleChnName) {
				// 同时检查角色名和角色中文名的唯一性约束
				msg = checkUnique(role);
			} else {
				if (checkRoleNameUnique(role.getName())) {
					msg = "角色ID已存在";
				}
			}
		} else {
			// 角色名没有作修改，只检查角色中文名的唯一性
			if (isEditRoleChnName) {
				if (checkRoleChnNameUnique(role.getName())) {
					msg = "角色名已存在";
				}
			}
		}

		if (msg != null) {
			result.put("message", msg);
			result.put("result", "error");
			return result;
		}

		roleApplication.updateEntity(role);
		result.put("result", "success");
		return result;
	}

	/**
	 * 删除角色
	 * 
	 * @param ids
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/deleteRoles")
	public Map<String, String> deleteRoles(String[] ids) {
		Map<String, String> result = new HashMap<String, String>();
		if (ids != null) {
			for (int i = 0; i < ids.length; i++) {
				RoleVO role = roleApplication.getEntity(ids[i]);
				if (role != null) {
					roleApplication.deleteEntity(role);
					rbacApplication.deleteByRoleId(role.getId());
				}

			}
		}
		result.put("result", "success");
		return result;
	}

	/**
	 * 增加用户与角色的关系
	 * 
	 * @param role
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/addUserByRoleID")
	public String addUser(RoleVO role) {
		if (role.getRolename().equals(""))
			return "failed";
		// roleApplication.deleteEntity(role);
		return "success";
	}

	/**
	 * 根据角色获取关联的用户
	 * 
	 * @param roleID
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/getUsersByRoleID")
	public Map<String, Object> getUsersByRoleID(String roleID) {
		Map<String, Object> result = new HashMap<String, Object>();
		List<UserVO> userList = rbacApplication.getUsersByRoleID(roleID);
		result.put("userList", userList);
		return result;
	}

	/**
	 * 根据角色是否有关联的用户
	 * 
	 * @param rolesID
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/checkRolesDepends")
	public Map<String, Object> checkRolesDepends(String[] ids) {
		Map<String, Object> result = new HashMap<String, Object>();
		List<String> roleNames = new ArrayList<String>();
		for (String roleID : ids) {
			List<UserVO> userList = rbacApplication.getUsersByRoleID(roleID);
			if (userList != null && userList.size() != 0) {
				RoleVO role = roleApplication.getEntity(roleID);
				roleNames.add(role.getName());
			}
		}
		result.put("roleName", roleNames);
		return result;
	}

	/**
	 * 删除角色表中的用户
	 * 
	 * @param roleID
	 * @param userIDs
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/deleteRoleUsers")
	public Map<String, String> deleteRoleUsers(String roleID, String[] userIDs) {
		Map<String, String> result = new HashMap<String, String>();
		rbacApplication.deleteUsersIDToRole(roleID, userIDs);
		result.put("result", "success");
		return result;
	}

	/**
	 * 新增角色表中的用户
	 * 
	 * @param roleID
	 * @param usersID
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/saveRoleUser")
	public Map<String, String> saveRoleUser(String roleID, String[] usersID) {
		Map<String, String> result = new HashMap<String, String>();
		List<String> users = Arrays.asList(usersID);
		rbacApplication.addUsersIdToRole(roleID, users);
		result.put("result", "success");
		return result;
	}

	/**
	 * 获取该角色没有的关联的用户
	 * 
	 * @param roleID
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/getMoreRoleUser")
	public List<UserVO> getMoreRoleUser(String roleID) {
		return rbacApplication.getMoreRoleUser(roleID);
	}

	/**
	 * 权限设置页面
	 * 
	 * @param model
	 * @return
	 */
	@RequestMapping("/privilege-view")
	public String listView(
			Model model,
			@RequestParam(value = "page", defaultValue = "1") int pageNumber,
			@RequestParam(value = "page.size", defaultValue = "10") int pageSize,
			HttpServletRequest request) {

		String queryUrl = "/rbac/privilege/privilege-view";
		QueryModelHelper queryHelper = new QueryModelHelper(queryUrl,
				makeQueryFields(), makeSortInfo());
		QuerySpecs querySpecs = queryHelper.populateQueryModel(model, request);
		Page<RoleVO> roleList = roleApplication.findRolesBySpec(pageNumber,
				pageSize, querySpecs);

		// Pageable pageable = new PageRequest(pageNumber-1, pageSize);
		// Page<RoleVO> roleList = roleApplication.findByPageable(pageable);

		// add by lizhfeng 下拉菜单选中内容应该与搜索相对应
		QueryFilter firstFilter = querySpecs.getFirstFilter();
		if (firstFilter.getFieldName() != null) {
			model.addAttribute(
					"fieldName",
					"q_" + firstFilter.getOperator().name() + "_"
							+ firstFilter.getFieldName());
		}
		model.addAttribute("page", new PageMustache(roleList, 10));
		model.addAttribute("roleList", roleList);
		// List<RoleVO> roleList = roleApplication.findAll();

		List<UserVO> userList = userApplication.findAll();
		model.addAttribute("userList", userList);

		return "rbac/rbac-privilege";
	}

	private final SelectBoxModel makeQueryFields() {
		SelectBoxModel sbm = new SelectBoxModel();
		sbm.addOption("LIKE_rolename", "角色ID");
		sbm.addOption("LIKE_name", "角色名");
		return sbm;
	}

	private final SortInfoModel makeSortInfo() {
		SortInfoModel sim = new SortInfoModel();
		sim.setSortEntry("rolename", "角色ID", true);
		sim.setSortEntry("name", "角色名", true);
		return sim;
	}

	/**
	 * 设置权限窗口
	 * 
	 * @param roleID
	 * @return
	 */

	@RequestMapping("showPrivileges")
	public String showPrivileges(@RequestParam String roleID, Model model) {
		List<AppMainVo> appResultList = this.appApplication.findAll();
		if ((appResultList != null) && (appResultList.size() > 0)) {
			model.addAttribute("appList", appResultList);
			model.addAttribute("appId", appResultList.get(0).getId());
		}
		model.addAttribute("roleID", roleID);
		return "rbac/rbac-app-view";
	}

	@RequestMapping("modules")
	public String showModules(@RequestParam("roleID") String roleID,
			@RequestParam("appId") String appId, Model model) {
		List<WidgetVO> widgetList = this.widgetApplication
				.getWidgetsForRbac(appId);
		if ((widgetList != null) && (widgetList.size() > 0)) {
			model.addAttribute("widgetList", widgetList);
			List<OperationVO> operationList = this.operationApplication
					.findAll();
			model.addAttribute("operationList", operationList);
		}
		model.addAttribute("roleID", roleID);
		model.addAttribute("appId", appId);
		return "rbac/rbac-modules-view";
	}

	@ResponseBody
	@RequestMapping("privileges")
	public List<PrivilegeVO> findPrivileges(
			@RequestParam("roleID") String roleID,
			@RequestParam("appId") String appId) {
		List<PrivilegeVO> privilegeList = this.privilegeApplication
				.getAppPrivilegeByRoleID(roleID, appId);

		if ((privilegeList != null) && (privilegeList.size() > 0)) {
			return privilegeList;
		}
		return new ArrayList();
	}

	/**
	 * 终端用户获取模块信息前，进行权限认证
	 * 
	 * 1.根据用户名查询相关的角色集 2.返回每个角色对应的所有权限 3.将权限全部归类合并
	 * 
	 * @param username
	 * @param appId
	 * @return
	 */

	@ResponseBody
	@RequestMapping("authorized")
	public Map<String, List> authorized(@RequestParam String username,
			@RequestParam String appId) {
		return privilegeApplication.authorize(username, appId);
	}

	/**
	 * 保存权限
	 * 
	 * @param privilegeList
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/savePrivileges")
	public Map<String, String> savePrivileges(String privilegeList) {
		Map<String, String> result = new HashMap<String, String>();
		try {
			JsonMapper jm = JsonMapper.nonEmptyMapper();
			JavaType javaType = jm.createCollectionType(ArrayList.class,
					PrivilegeVO.class);
			List<PrivilegeVO> privileges = jm.fromJson(privilegeList, javaType);
			if ((privileges != null) && (privileges.size() > 0)) {
				String roleID = ((PrivilegeVO) privileges.get(0)).getRole_ID();
				String appID = ((PrivilegeVO) privileges.get(0)).getApp_ID();
				List<PrivilegeVO> orgPrivileges = this.privilegeApplication
						.getAppPrivilegeByRoleID(roleID, appID);
				this.privilegeApplication.deletePrivilegesByRoleIDs(roleID,
						appID);
				for (PrivilegeVO privilegeVO : privileges) {
					this.privilegeApplication.saveEntity(privilegeVO);
				}
				result.put("result", "success");
				try {
					pushMessage(orgPrivileges, privileges);
				} catch (Exception e) {
					e.printStackTrace();
					this.log.error("pushMessage", e);
				}
			}
		} catch (Exception e) {
			this.log.error("savePrivileges", e);
			result.put("result", "error");
		}
		return result;
	}

	private void pushMessage(List<PrivilegeVO> orgPrivileges,
			List<PrivilegeVO> destPrivileges) {
		Map<String, String> map = new HashMap<String, String>();
		if ((orgPrivileges != null) && (orgPrivileges.size() > 0)) {
			for (PrivilegeVO vo : orgPrivileges) {// 遍历数据库里面，每个模块对应的授权操作id字符串
				map.put(vo.getModule_ID(), vo.getOperation_IDs().toString());
			}
		}
		MessageParams msgParams = new MessageParams();
		String roleId = ((PrivilegeVO) destPrivileges.get(0)).getRole_ID();
		String appId = ((PrivilegeVO) destPrivileges.get(0)).getApp_ID();
		String appKey = this.applicationRegisterApplication
				.getAppKeyByAppId(appId);
		RoleVO remoteRole = this.roleApplication.getEntity(roleId);
		Map<String, String> tags = new HashMap<String, String>();
		tags.put("role", remoteRole.getName());
		msgParams.setTags(tags);
		msgParams.setAppId(appKey);
		msgParams.setReceiverType(ReceiverTypeEnumVo.TAG);
		MessageVo messageVo = new MessageVo();
		messageVo.setMessageType(MessageVo.MessageTypeEnum.SECURITY);
		messageVo.setTitle("安全策略更新");
		messageVo.putExtra("securityKey", "privilege");// 授权变更
		msgParams.setMessage(messageVo);
		boolean flag = false;
		if ((destPrivileges != null) && (destPrivileges.size() > 0)) {
			for (PrivilegeVO privilegeVO : destPrivileges) {// 遍历更新提交的每个模块对应的授权操作id字符串
				if (!map.containsKey(privilegeVO.getModule_ID())) {// 如果数据库不存在该模块，则是新增一个模块授权，需要推送消息
					flag = true;
					break;
				} else {// 如果数据库存在该模块，但是操作权限修改了，也需要推送消息
					String peration_IDs = map.get(privilegeVO.getModule_ID());// 原数据库授权操作id字符串
					String destperation_IDs = privilegeVO.getOperation_IDs()// 变更授权操作id字符串
							.toString();
					if (!peration_IDs.equals(destperation_IDs)) {
						flag = true;
						break;
					}
				}
			}

			if (flag) {
				String pushRequestId = this.pushService
						.submitMessage(msgParams);

				this.log.info("[submitMessage]用户角色绑定模块变更，推送消息返回结果："
						+ pushRequestId);
			} else if (destPrivileges.size() != map.size()) {
				String pushRequestId = this.pushService
						.submitMessage(msgParams);

				this.log.info("[submitMessage]用户角色绑定模块变更，推送消息返回结果："
						+ pushRequestId);
			}
		} else {
			String pushRequestId = this.pushService.submitMessage(msgParams);
			this.log.info("[submitMessage]用户角色绑定模块变更，推送消息返回结果：" + pushRequestId);
		}
	}

}
